﻿package yuyicman.effects {
	
	import flash.display.*;
	import flash.events.*;
	import flash.geom.*;
	import flash.utils.*;
	import gs.easing.*;

	public class Switch extends EventDispatcher {
		
		private var isDefRect:Boolean = false;
		private var completeType:Object = 0;
		private var _type:String;
		private var faceList:Array;
		private var _targetScaleY:Object = 1;
		private var ownRect:Rectangle;
		private var _targetScaleX:Object = 1;
		private var _endRect:Rectangle;
		private var _time:Number;
		private var _segmentsT:Number = 2;
		private var _rect:Rectangle;
		private var removeTarget:Boolean = true;
		private var timer:Timer;
		private var _endvars:Object;
		private var _parent:DisplayObjectContainer;
		private var minW:Number;
		private var minDur:Number = 0.2;
		private var _startTime:Date;
		private var index:Number;
		private var _cacheBitmapData:BitmapData;
		private var easingList:Object;
		private var geometry:Array;
		private var _duration:Number;
		private var _segments:Number;
		
		public var rect:Rectangle;
		public var _target:DisplayObject;
		public var _cacheDisplay:Shape;
		
		static public  var defSegments:Number = 3;

		public function Switch(tar:DisplayObject, dur:Number, o:Object) {
			_segmentsT = 2;
			minDur = 0.2;
			isDefRect = false;
			_targetScaleX = 1;
			_targetScaleY = 1;
			completeType = 0;
			removeTarget = true;
			readVars(tar, dur, o);
		}

		public function get target():DisplayObject {
			return _target;
		}

		private function drawCache(param1:*):void {
			
			var mtx:Matrix = new Matrix();
			var graphic:Graphics = _cacheDisplay.graphics;
			var timeStep:Number = ((new Date).getTime() - _startTime.getTime()) / 1000;
			var i:int;
			var point1:Array;
			var point2:Array;
			var point3:Array;
			var _loc_11:Number;
			var _loc_12:Number;
			var _loc_13:Number;
			var _loc_14:Number;
			var _loc_15:Number;
			var _loc_16:Number;
			var _loc_17:Number;
			var _loc_18:Number;
			var _loc_19:Number;
			var tarInd:int;
			var cacheParent:DisplayObjectContainer;
			
			timeStep = ((new Date).getTime() - _startTime.getTime()) / 1000;

			for (i = 0; i<geometry.length; i++) {
				if (timeStep >= geometry[i][2]) {
					geometry[i][0] = geometry[i][9];
					geometry[i][1] = geometry[i][10];
					continue;
				}
				_loc_11 = timeStep / geometry[i][2];
				if (_type == "x1" || _type=="x2") {
					geometry[i][0] = Quint.easeInOut(timeStep, geometry[i][7], geometry[i][3], geometry[i][2]);
					geometry[i][1] = Sine.easeInOut(timeStep, geometry[i][8], geometry[i][4], geometry[i][2]);
					continue;
				}
				
				geometry[i][1] = Quint.easeInOut(timeStep, geometry[i][8], geometry[i][4], geometry[i][2]);
				geometry[i][0] = Sine.easeInOut(timeStep, geometry[i][7], geometry[i][3], geometry[i][2]);
			}
			_cacheBitmapData.lock();
			graphic.clear();

			for (i = 0; i<faceList.length; i++) {
				point1 = geometry[faceList[i][0]];
				point2 = geometry[faceList[i][1]];
				point3 = geometry[faceList[i][2]];
				_loc_12 = point2[0] - point1[0];
				_loc_13 = point3[0] - point1[0];
				_loc_16 = point2[1] - point1[1];
				_loc_17 = point3[1] - point1[1];
				_loc_14 = point2[5] - point1[5];
				_loc_15 = point3[5] - point1[5];
				_loc_18 = point2[6] - point1[6];
				_loc_19 = point3[6] - point1[6];
				mtx.a = (_loc_13 * _loc_18 - _loc_12 * _loc_19) / (_loc_15 * _loc_18 - _loc_14 * _loc_19);
				mtx.b = (_loc_17 * _loc_18 - _loc_16 * _loc_19) / (_loc_18 * _loc_15 - _loc_14 * _loc_19);
				mtx.c = (_loc_13 * _loc_14 - _loc_12 * _loc_15) / (_loc_14 * _loc_19 - _loc_18 * _loc_15);
				mtx.d = (_loc_17 * _loc_14 - _loc_16 * _loc_15) / (_loc_19 * _loc_14 - _loc_18 * _loc_15);
				mtx.tx = point1[0] - (mtx.a * point1[5] + point1[6] * mtx.c);
				mtx.ty = point1[1] - (mtx.d * point1[6] + point1[5] * mtx.b);
				graphic.beginBitmapFill(_cacheBitmapData, mtx, false, true);
				graphic.moveTo(point1[0], point1[1]);
				graphic.lineTo(point2[0], point2[1]);
				graphic.lineTo(point3[0], point3[1]);
				graphic.lineTo(point1[0], point1[1]);
				graphic.endFill();
				dispatchEvent(new Event("SwitchDrawComplete"));
			}
			_cacheBitmapData.unlock();
			if (timeStep >= _duration) {
				timer.stop();
				if (completeType == 0) {
					if (_cacheDisplay.parent) {
						_cacheDisplay.parent.removeChild(_cacheDisplay);
					}
				} else if (completeType == 1) {
				} else if (completeType == 2) {
					if (_cacheDisplay.parent) {
						tarInd = targetIndex;
						cacheParent = _cacheDisplay.parent;
						_cacheDisplay.parent.removeChild(_cacheDisplay);
						cacheParent.addChildAt(_target, tarInd);
						_target.width = rect.width;
						_target.height = rect.height;
						_target.x = rect.x - ownRect.x * _target.scaleX;
						_target.y = rect.y - ownRect.y * _target.scaleY;
					}
				}
				dispatchEvent(new Event("SwitchMoveComplete"));
			}
		}

		public function get targetIndex():int {
			if (_cacheDisplay.parent) {
				return _cacheDisplay.parent.getChildIndex(_cacheDisplay);
			}
			return -1;
		}

		private function creatCache():Boolean {
			var hStep:Number;
			var vStep:Number;
			var end_hStep:Number;
			var end_vStep:Number;
			var own_hStep:Number;
			var own_vStep:Number;
			var hVec:Number;
			var vVec:Number;
			var endhVec:Number;
			var endvVec:Number;
			var mtx:Matrix = new Matrix();

			var durationSeg:*;
			var rectCenterX:Number;
			var rectCenterY:Number;
			var distX:Number;
			var distY:Number;

			durationSeg = (_duration - minDur) / _segments;
			_cacheDisplay = new Shape();
			if (removeTarget) {
				if (_target.parent) {
					_target.parent.removeChild(_target);
				}
			}
			if (index != -1) {
				_parent.addChildAt(_cacheDisplay, index);
			} else {
				_parent.addChild(_cacheDisplay);
			}
			if (Math.ceil(ownRect.width) <= 0 || Math.ceil(ownRect.height) <= 0) {
				return false;
			}
			if (isDefRect) {
				mtx.translate(-ownRect.x, -ownRect.y);
				_cacheBitmapData = new BitmapData(Math.ceil(ownRect.width), Math.ceil(ownRect.height), true, 0);
				_cacheBitmapData.draw(_target, mtx);
			} else {
				mtx.translate(-ownRect.x, -ownRect.y);
				_cacheBitmapData = new BitmapData(Math.ceil(ownRect.width), Math.ceil(ownRect.height), true, 0);
				_cacheBitmapData.draw(_target, mtx);
			}
			_cacheDisplay.x = _rect.x;
			_cacheDisplay.y = _rect.y;
			rectCenterX = _rect.x + _rect.width / 2;
			rectCenterY = _rect.y + _rect.height / 2;
			_endvars.x = _endRect.x + _endRect.width / 2;
			_endvars.y = _endRect.y + _endRect.height / 2;
			distX = Math.abs(rectCenterX - _endvars.x) - (_rect.width + _endRect.width) / 2;
			distY = Math.abs(rectCenterY - _endvars.y) - (_rect.height + _endRect.height) / 2;
			if (_rect.intersects(_endRect)) {
				if (distX > distY) {
					if (_endvars.x > rectCenterX) {
						_type = "y1";
					} else {
						_type = "y2";
					}
				} else if (_endvars.y > rectCenterY) {
					_type = "x1";
				} else {
					_type = "x2";
				}
			} else if (distX >= 0 && distY >= 0) {
				if (distX > distY) {
					if (_endvars.x > rectCenterX) {
						_type = "y1";
					} else {
						_type = "y2";
					}
				} else if (_endvars.y > rectCenterY) {
					_type = "x1";
				} else {
					_type = "x2";
				}
			} else if (distX >= 0) {
				if (_endvars.x > rectCenterX) {
					_type = "y1";
				} else {
					_type = "y2";
				}
			} else if (_endvars.y > rectCenterY) {
				_type = "x1";
			} else {
				_type = "x2";
			}
			geometry = [];
			faceList = [];
			if (_type == "x1" || _type == "x2") {
				hStep = _rect.height / _segments;
				vStep = _rect.width / _segmentsT;
				end_hStep = _endRect.height / _segments;
				end_vStep = _endRect.width / _segmentsT;
				own_hStep = ownRect.height / _segments;
				own_vStep = ownRect.width / _segmentsT;
			} else {
				hStep = _rect.width / _segments;
				vStep = _rect.height / _segmentsT;
				end_hStep = _endRect.width / _segments;
				end_vStep = _endRect.height / _segmentsT;
				own_hStep = ownRect.width / _segments;
				own_vStep = ownRect.height / _segmentsT;
			}
			var i:uint;
			var j:uint;
			for (i = 0; i<=_segments; i++) {
				for (j = 0; j<=_segmentsT; j++) {
					if (_type == "x1") {
						vVec = vStep * j;
						hVec = hStep * i;
						endhVec = _endRect.x - _rect.x + end_vStep * j;
						endvVec = _endRect.y - _rect.y + end_hStep * i;
						geometry[i * (_segmentsT + 1) + j] = [vVec, hVec, minDur + (_segments - i) * durationSeg, endhVec - vVec, endvVec - hVec, j * own_vStep, own_hStep * i, vVec, hVec, endhVec, endvVec];
					} else if (_type == "x2") {
						vVec = j * vStep;
						hVec = hStep * i;
						endhVec = _endRect.x - _rect.x + end_vStep * j;
						endvVec = _endRect.y - _rect.y + end_hStep * i;
						geometry[i * (_segmentsT + 1) + j] = [vVec, hVec, minDur + i * durationSeg, endhVec - vVec, endvVec - hVec, j * own_vStep, i * own_hStep, vVec, hVec, endhVec, endvVec];
					} else if (_type == "y1") {
						vVec = i * hStep;
						hVec = vStep * j;
						endhVec = _endRect.x - _rect.x + end_hStep * i;
						endvVec = _endRect.y - _rect.y + end_vStep * j;
						geometry[i * (_segmentsT + 1) + j] = [vVec, hVec, minDur + (_segments - i) * durationSeg, endhVec - vVec, endvVec - hVec, i * own_hStep, j * own_vStep, vVec, hVec, endhVec, endvVec];
					} else if (_type == "y2") {
						vVec = i * hStep;
						hVec = vStep * j;
						endhVec = _endRect.x - _rect.x + end_hStep * i;
						endvVec = _endRect.y - _rect.y + end_vStep * j;
						geometry[i * (_segmentsT + 1) + j] = [vVec, hVec, minDur + i * durationSeg, endhVec - vVec, endvVec - hVec, i * own_hStep, j * own_vStep, vVec, hVec, endhVec, endvVec];
					}
					if (i > 0 && j > 0) {
						faceList.push([( (i-1) * (_segmentsT + 1) + j)-1, (i-1) * (_segmentsT + 1) + j, i * (_segmentsT + 1) + j]);
						faceList.push([((i-1) * (_segmentsT + 1) + j)-1, i * (_segmentsT + 1) + j, (i * (_segmentsT + 1) + j)-1]);
					}
				}
			}
			_startTime = new Date();
			timer = new Timer(25, 0);
			timer.addEventListener(TimerEvent.TIMER, drawCache);
			timer.start();
			drawCache(null);
			return true;
		}

		private function readVars(tar:DisplayObject, dur:Number, o:Object):void {
			var bounds:Rectangle;
			_target = tar;
			_duration = dur;
			if (o.parent != null) {
				_parent = o.parent;
				bounds = _target.getBounds(_parent);
			} else if (_target.parent) {
				_parent = _target.parent;
				bounds = _target.getBounds(_parent);
			} else {
				_parent = null;
				index = -1;
				return;
			}
			if (o.removeTarget != null) {
				removeTarget = o.removeTarget;
			}
			if (_target.parent && _target.parent.stage) {
				index = _target.parent.getChildIndex(_target);
			} else {
				if (_target.parent) {
					_target.parent.removeChild(_target);
				}
				index = -1;
			}
			if (_target.parent == o.parent) {
			} else {
				index = -1;
			}
			_targetScaleX = _target.scaleX;
			_targetScaleY = _target.scaleY;
			
			minDur = _duration * 0.4;
			_time = 0;
			_endvars = {};
			if (o.segments != null) {
				_segments = o.segments;
			} else {
				_segments = defSegments;
			}
			if (o._segmentsT != null) {
				_segmentsT = o._segmentsT;
			}
			if (o.completeType != null) {
				completeType = o.completeType;
			}
			ownRect = _target.getBounds(_target);
			if (o.rect != null) {
				_rect = o.rect;
				isDefRect = false;
			} else {
				isDefRect = true;
				_rect = bounds;
			}
			var wRatio:Number = ownRect.width / bounds.width;
			var hRatio:Number = ownRect.height / bounds.height;
			ownRect.x = _rect.x * wRatio + (ownRect.x - bounds.x * wRatio);
			ownRect.y = _rect.y * hRatio + (ownRect.y - bounds.y * hRatio);
			ownRect.width = _rect.width * wRatio;
			ownRect.height = _rect.height * hRatio;
			if (o.endRect != null) {
				_endRect = new Rectangle(o.endRect.x, o.endRect.y, o.endRect.width, o.endRect.height);
				rect = _endRect.clone();
			} 
			else {
				return;
			}
			creatCache();
			return;
		}

		public static function to(tar:DisplayObject, dur:Number, o:Object):Switch {
			return new Switch(tar,dur,o);
		}
	}
}